package com.yyge.common.controller;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yyge.common.callback.PageCallback;
import com.yyge.common.util.ReflectionUtil;
import com.yyge.common.vo.resp.PageResp;
import com.yyge.controller.admin.mapstruct.BeanConverter;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Controller的父类用于存放公共方法
 * @param <T> Controller对应的实体类
 * @param <N> 实体类对应的Resp
 */

public class BaseController<T,N> {

    public Class<?> converter;

    @Autowired
    private ReflectionUtil reflectionUtil;

    /**
     * 分页查询的分页对象
     * @param callback Aop切面
     * @return PageResp
     */
    public PageResp page(Object req,PageCallback callback) throws Exception {
      Method getPage = req.getClass().getMethod("getPage");
      Method getSize = req.getClass().getMethod("getSize");
      Integer page = (Integer) getPage.invoke(req);
      Integer size = (Integer) getSize.invoke(req);

      Page pageInfo = new Page<>();
      page = page==null ? 1:page;
      size = size==null ? 10:size;
      pageInfo.setCurrent(page);
      pageInfo.setSize(size);
      pageInfo = callback.doPage(pageInfo);
      Object list = autoConverter(pageInfo.getRecords());

      PageResp pageVo= BeanConverter.MAPPER.page2vo(pageInfo);
      pageVo.setRows((List) list);
      return pageVo;
    }

    /**
     * 利用反射对对象进行进行转换
     * @param req 转换完成之后的类型(注意：虽然是Objec 但是实际上是转换之后的类型)
     * @return Object 转换完毕之后的对象 Object
     */
   public Object autoConverter(Object req) throws Exception {
       //优先级：req>str

       //获取参数的类名称
       String argName,reqStr;
       //当有req的时候才会取值到req
       argName=req.getClass().getSimpleName();
       if(argName.equalsIgnoreCase("ArrayList")){
           argName="List";
       }
       reqStr=argName.substring(argName.length()-3).toLowerCase();
       Field field = this.converter.getDeclaredField("MAPPER");
       Object mapper = field.get(null).getClass().newInstance();

       /**
        * 自动换换 如果传进来的是List 则返回List的对应结果
        * 如果传进来的是Req 则 转化为 Entity
        * 如果传进来的是Entity 则转化为 Resp
        */
       Method arg = reflectionUtil.isContainsArgs(mapper.getClass(),argName);
       if(!Objects.isNull(arg)){
            return arg.invoke(mapper,req);
       }


       return null;
   }

    /**
     * 导出集合数据到excel表中
     * @param response
     * @param cls
     * @param arrList
     * @param <T>
     * @throws IOException
     */
    public <T> void writeListToExcel(HttpServletResponse response, Class<T> cls, List<T> arrList) throws IOException {
        //设定输出到浏览器的格式   .xlsx 对应的 mime-type类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        // 文件名
        String fileName = System.currentTimeMillis() + ".xlsx";
        //设定给浏览器，告诉响应给浏览器文件名
        response.setHeader("Content-disposition", "attachment;filename="+fileName);

        EasyExcel.write(response.getOutputStream(), cls).sheet("内容").doWrite(arrList);
    }

    public T getEntity(Object req) throws Exception {
        //转换类型为原始的Entity类型 方便查询
        return (T)autoConverter(req);
    }

    public T getEntity() throws Exception {
        T t = null;
        return (T)t.getClass().newInstance();
    }

    public N getResp(T t) throws Exception {
        //转换类型为原始的Entity类型 方便查询
        return (N)autoConverter(t);
    }

    public QueryWrapper<T> getWrapper(Object req) throws Exception {
        //转换类型为原始的Entity类型 方便查询
        Object autoed = this.autoConverter(req);

        //实例化QueryWrapper
        QueryWrapper<T> wrapper = new QueryWrapper<>();

        //获取实体所有对应的列
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(autoed.getClass());
        for (Field field : reflectionUtil.getFieldNames(autoed)) {
            Class<?> Obj = autoed.getClass();
            if (field.getType().equals(String.class)) {
                String MethodName = "get" + (field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
                // 获取方法
                Method method = Obj.getMethod(MethodName);

                // 调用方法
                Object result = method.invoke(autoed);
                String column = columnMap.get(LambdaUtils.formatKey(field.getName())).getColumn();
                wrapper.like(column, result);
            }
        }
        return wrapper;
    }

    public QueryWrapper<T> getWrapper() {
        return new QueryWrapper<T>();
    }
    public LambdaQueryWrapper<T> getLambdaWrapper() throws Exception {
        return new LambdaQueryWrapper<T>();
    }
    public UpdateWrapper<T> getUpdataWrapper() throws Exception {
        return new UpdateWrapper<T>();
    }
    public LambdaUpdateWrapper<T> getLambdaUpdateWrapper() throws Exception {
        return new LambdaUpdateWrapper<T>();
    }
}
